package me.aartikov.alligator.helpers;

import me.aartikov.alligator.util.Log;
import me.aartikov.alligator.animations.TransitionAnimation;
import me.aartikov.alligator.Screen;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.FractionManager;
import ohos.aafwk.ability.fraction.FractionScheduler;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;

import static me.aartikov.alligator.converters.DefaultFragmentConverter.KEY_SCREEN;

/**
 * Fraction 运行栈
 */
public class FractionStack {
    private  AnimatorValue animatorValue = new AnimatorValue();

    private FractionManager fractionManager;

    private List<MiFraction> stackFragment;

    private static volatile HashMap<FractionManager, FractionStack>
            fractionManagerFragmentStackHashMap = new HashMap<>();

    /**
     * 获取当前栈中的Fraction列表
     *
     * @return List<MiFraction>
     */
    public List<MiFraction> getStackFragment() {
        return stackFragment;
    }

    private FractionStack(FractionManager fractionManager) {
        this.fractionManager = fractionManager;
        stackFragment = new ArrayList<>();
    }

    /**
     * 清除回退栈
     */
    public void clear() {
        fractionManagerFragmentStackHashMap.clear();
        stackFragment.clear();
    }

    /**
     * 通过fractionmanage获取栈
     *
     * @param fractionManager 绑定栈的FractionManager
     * @return FractionStack
     */
    public static FractionStack getInstance(FractionManager fractionManager) {
        HashMap<FractionManager, FractionStack>
                locKfractionManagerFragmentStackHashMap = fractionManagerFragmentStackHashMap;
        if (locKfractionManagerFragmentStackHashMap == null) {
            synchronized (FractionStack.class) {
                locKfractionManagerFragmentStackHashMap = fractionManagerFragmentStackHashMap;
                if (locKfractionManagerFragmentStackHashMap == null) {
                    locKfractionManagerFragmentStackHashMap = fractionManagerFragmentStackHashMap = new HashMap<>();
                }
            }
        }
        FractionStack fragmentStack = locKfractionManagerFragmentStackHashMap.get(fractionManager);
        if (fragmentStack == null) {
            fragmentStack = new FractionStack(fractionManager);
            locKfractionManagerFragmentStackHashMap.put(fractionManager, fragmentStack);
        }
        return fragmentStack;
    }

    /**
     * 弹出fraction
     *
     * @param screen    fraction绑定的screen
     * @param animation 动画
     * @return boolean
     */
    public boolean pop(Screen screen, TransitionAnimation animation) {
        return pop(FractionCache.getInstance().get(screen), animation);
    }

    /**
     * 弹出fraction
     *
     * @param mCurrentFragment 需要弹出的fraction
     * @param animation        动画
     * @return 是否弹出成功
     */
    public boolean pop(MiFraction mCurrentFragment, TransitionAnimation animation) {
        boolean isRemoveFragment = false;
        int count = stackFragment.size();
        if (count == 0) {
            throw new IllegalStateException("Can't pop fragment when stack is empty.");
        }
        MiFraction currentFragment = mCurrentFragment;
        MiFraction previousFragment = null;
        if (currentFragment == null) {
            currentFragment = stackFragment.get(count - 1);
            previousFragment = stackFragment.size() > 1 ? stackFragment.get(stackFragment.size() - 2) : null;
        } else {
            List<MiFraction> groupFragment = getGourpFragment(currentFragment.getGouptag().toString());
            if (groupFragment.size() > 1) {
                previousFragment = groupFragment.get(groupFragment.size() - 2);
            }
        }

        FractionScheduler transaction = fractionManager.startFractionScheduler();
        if (animation != null) {
            animation.applyBeforeFragmentTransactionExecuted(transaction, previousFragment, currentFragment);
        }

        if (previousFragment != null) {
            // 如果相邻的两个fragment不属于同一个分组
            if (previousFragment.getGouptag() != currentFragment.getGouptag()) {
                List<MiFraction> previousFragments = getGourpFragment(currentFragment.getGouptag().toString());
                if (previousFragments.size() > 1) {
                    previousFragment = previousFragments.get(previousFragments.size() - 1);
                } else {
                    return pop(previousFragment, animation);
                }
            }
        } else {
            if (currentFragment.getGouptag() instanceof Ability) {
                ((Ability) (currentFragment.getGouptag())).terminateAbility();
            }
        }
        stackFragment.remove(currentFragment);
        removeAllFragmentByGroup(currentFragment.toString());
        isRemoveFragment = doPop(transaction, animation, currentFragment, previousFragment);

        if (animation != null) {
            animation.applyAfterFragmentTransactionExecuted(previousFragment, currentFragment);
        }
        return isRemoveFragment;
    }

    private boolean doPop(FractionScheduler transaction,
        TransitionAnimation animation, MiFraction currentFragment, MiFraction previousFragment) {
        boolean isRemoveFragment = false;
        if (previousFragment != null) {
            if (animation != null) {
                Log.i("退出  FragmentStack.pop([currentFragment, animation]):131");
                startFragmentAnimal(fractionManager, currentFragment, previousFragment, animation, true);
            } else {
                FractionCache.getInstance().removeFragment(currentFragment);
                transaction.replace(previousFragment.getParentId(), previousFragment);
                transaction.submit();
                removeAllFragmentByGroup(currentFragment.toString());
            }
            isRemoveFragment = true;
        } else {
            isRemoveFragment = false;
        }
        return isRemoveFragment;
    }

    /**
     * 删除所有此分组的fragment
     *
     * @param group 分组
     */
    public void removeAllFragmentByGroup(String group) {
        stackFragment.removeAll(getGourpFragment(group));
    }

    /**
     * 弹出faction
     *
     * @param fragment  需要弹出的fraction
     * @param animation 动画
     * @return boolean
     */
    public boolean popUntil(MiFraction fragment, TransitionAnimation animation) {
        List<MiFraction> fragments = getGourpFragment(fragment.getGouptag().toString());
        int count = fragments.size();

        int index = fragments.indexOf(fragment);
        if (index == -1) {
            throw new IllegalArgumentException("Fragment is not found.");
        }

        if (index == count - 1) {
            return false;
        }
        FractionScheduler scheduler = fractionManager.startFractionScheduler();
        for (int i = index + 1; i < count; i++) {
            if (i == count - 1) {
                animation.applyBeforeFragmentTransactionExecuted(scheduler, fragment, fragments.get(i));
            }
            scheduler.remove(fragments.get(i));
        }
        scheduler.show(fragment);
        scheduler.submit();

        animation.applyAfterFragmentTransactionExecuted(fragment, fragments.get(count - 1));

        return true;
    }


    /**
     * Packet data of fragment
     *
     * @param group fragment group tag
     * @return Packet data of fragment
     */
    public List<MiFraction> getGourpFragment(String group) {
        List<MiFraction> groupFragment = new ArrayList<MiFraction>() {
            @Override
            public MiFraction remove(int index) {
                if (stackFragment.get(index) instanceof MiFraction) {
                    FractionCache.getInstance().removeFragment(stackFragment.get(index));
                }
                stackFragment.remove(index);
                return super.remove(index);
            }

            @Override
            public boolean remove(Object coll) {
                stackFragment.remove(coll);
                if (coll instanceof MiFraction) {
                    FractionCache.getInstance().removeFragment((MiFraction) coll);
                }
                return super.remove(coll);
            }

            @Override
            public boolean removeAll(Collection<?> coll) {
                stackFragment.removeAll(coll);
                for (int i = 0; i < stackFragment.size(); i++) {
                    FractionCache.getInstance().removeFragment(stackFragment.get(i));
                }
                return super.removeAll(coll);
            }

            @Override
            public boolean add(MiFraction fragment) {
                if (!stackFragment.contains(fragment)) {
                    stackFragment.add(fragment);
                }
                return super.add(fragment);
            }

            @Override
            public void add(int index, MiFraction element) {
                if (stackFragment.indexOf(get(index)) != -1) {
                    stackFragment.remove(stackFragment.indexOf(get(index)));
                }
                stackFragment.add(element);
                super.add(index, element);
            }
        };
        groupFragment = groupFragment(groupFragment, stackFragment, group);
        return groupFragment;
    }


    private List<MiFraction> groupFragment(List<MiFraction> groupFragment,
                                           List<MiFraction> stackFragment,
                                           String group) {
        for (int i = 0; i < stackFragment.size(); i++) {
            if (stackFragment.get(i).getGouptag() != null
                    && stackFragment.get(i).getGouptag().toString().equals(group)) {
                groupFragment.add(stackFragment.get(i));
            } else {
                break;
            }
        }
        return groupFragment;
    }

    /**
     * 获取当前栈顶的fraction
     *
     * @return MiFraction
     */
    public MiFraction getCurrentFragment() {
        if (stackFragment.size() > 0) {
            return stackFragment.get(stackFragment.size() - 1);
        }
        return null;
    }


    /**
     * 获取fraction分组中的最前的fraction
     *
     * @param fragment 需要区分的fraction分组
     * @return MiFraction
     */
    public MiFraction getCurrentFragment(MiFraction fragment) {
        List<MiFraction> groupFragment = getGourpFragment(fragment.getGouptag().toString());
        if (groupFragment.size() > 0) {
            return groupFragment.get(groupFragment.size() - 1);
        }
        return null;
    }

    /**
     * 通过分组标示获取到当前分组对应的所有screen
     *
     * @param group 分组的tag
     * @return List<Screen>
     */
    public List<Screen> getCurrentFragmentScreen(String group) {
        List<Screen> list = new ArrayList<>();
        List<MiFraction> groupFragment = getGourpFragment(group);
        for (int i = 0; i < groupFragment.size(); i++) {
            list.add((Screen) groupFragment.get(i).getIntentParams().getParam(KEY_SCREEN));
        }
        return list;
    }

    /**
     * 将fraction加入到栈中
     *
     * @param fragment  需要加入到栈中的fraction
     * @param animation 动画
     * @return 是否加入成功
     */
    public boolean push(MiFraction fragment, TransitionAnimation animation) {
        FractionScheduler scheduler = fractionManager.startFractionScheduler();
        List<MiFraction> fragments = getGourpFragment(fragment.getGouptag().toString());
        MiFraction currentFragment = null;
        if (fragments.size() > 0) {
            currentFragment = fragments.get(fragments.size() - 1);
        }
        if (fragments.contains(fragment)) {
            fragments.remove(fragment);
        }
        fragments.add(fragment);
        if (animation != null) {
            animation.applyBeforeFragmentTransactionExecuted(scheduler, fragment, currentFragment);
        }
        if (animation != null && currentFragment != null && currentFragment.getComponent() != null) {
            startFragmentAnimal(fractionManager, currentFragment, fragment, animation, false);
        } else {
            scheduler.replace(fragment.getParentId(), fragment);
            scheduler.submit();
        }
        if (animation != null) {
            animation.applyAfterFragmentTransactionExecuted(fragment, currentFragment);
        }
        return true;
    }

    /**
     * 替换fraction
     *
     * @param fragment  需要替换的fraction
     * @param animation 动画
     * @return 是否成功
     */
    public boolean replace(MiFraction fragment, TransitionAnimation animation) {
        FractionScheduler scheduler = fractionManager.startFractionScheduler();
        List<MiFraction> groupFragment = getGourpFragment(fragment.getGouptag().toString());

        MiFraction currentFragment = null;
        if (groupFragment != null && groupFragment.size() > 0) {
            currentFragment = groupFragment.get(groupFragment.size() - 1);
            fragment.setParentId(currentFragment.getParentId());
            groupFragment.add(groupFragment.size() - 1, fragment);
        } else {
            groupFragment.add(fragment);
        }

        if (animation != null && currentFragment != null) {
            animation.applyBeforeFragmentTransactionExecuted(scheduler, fragment, currentFragment);
            startFragmentAnimal(fractionManager, currentFragment, fragment, animation, false);
            animation.applyAfterFragmentTransactionExecuted(fragment, currentFragment);
        } else {
            scheduler.replace(fragment.getParentId(), fragment);
            scheduler.submit();
        }
        return true;
    }

    /**
     * 重置栈中的数据
     *
     * @param fragment  通过此fraction获取到分组数据
     * @param animation 动画
     * @return 是否成功
     */
    public boolean reset(MiFraction fragment, TransitionAnimation animation) {
        FractionScheduler fractionScheduler = fractionManager.startFractionScheduler();
        List<MiFraction> fragments = getGourpFragment(fragment.getGouptag().toString());
        List<MiFraction> needClear = new ArrayList<>();
        MiFraction currentFragment = null;
        for (int i = 0; i < fragments.size(); i++) {
            if (i == fragments.size() - 1) {
                currentFragment = fragments.get(i);
                if (animation != null) {
                    animation.applyBeforeFragmentTransactionExecuted(fractionScheduler, fragment, currentFragment);
                }
            }
            if (!fragments.contains(fragment)) {
                fractionScheduler.remove(fragments.get(i));
            }
            needClear.add(fragments.get(i));
        }
        fractionScheduler.replace(fragment.getParentId(), fragment);
        fragments.removeAll(needClear);
        fragments.add(fragment);

        fractionScheduler.show(fragment);
        fractionScheduler.submit();

        if (animation != null) {
            animation.applyAfterFragmentTransactionExecuted(fragment, currentFragment);
        }
        return true;
    }

    /**
     * 还原fraction组数据
     *
     * @param fragments 需要还原的数据
     * @return 是否成功
     */
    public boolean reduce(List<MiFraction> fragments) {
        FractionScheduler fractionScheduler = fractionManager.startFractionScheduler();
        MiFraction nowShow = null;
        for (int i = 0; i < fragments.size(); i++) {
            if (stackFragment.contains(fragments.get(i))) {
                stackFragment.remove(fragments.get(i));
            }
            stackFragment.add(fragments.get(i));
            if (i == fragments.size() - 1) {
                nowShow = fragments.get(i);
            }
        }
        if (nowShow != null) {
            fractionScheduler.replace(nowShow.getParentId(), nowShow);
            fractionScheduler.submit();
            return true;
        } else {
            return false;
        }
    }


    /**
     * 执行fraction加载
     *
     * @param fractionManager       fractionManager
     * @param exitFragment          需要退出的fraction
     * @param enterFragment         需要加载的fraction
     * @param animation             动画
     * @param isRemoveFragmentFroup 是否需要清除退出的fraction对应得所有分组
     */

    public void startFragmentAnimal(FractionManager fractionManager,
    MiFraction exitFragment, MiFraction enterFragment,TransitionAnimation animation,
        boolean isRemoveFragmentFroup) {
        if (animatorValue.isRunning()) {
            animatorValue.end();
            animatorValue.stop();
        }
        animatorValue = new AnimatorValue();
        animatorValue.setDuration(300);
        exitFragment.setOutAnimal(animation.getExitAnimal());
        enterFragment.setEnterAnimal(animation.getEnterAnimal());
        startFragmentAnimal(fractionManager, exitFragment, enterFragment, isRemoveFragmentFroup);
        animatorValue.start();
    }


    /**
     * 执行fraction加载
     *
     * @param fractionManager       fractionManager
     * @param exitFragment          需要退出的fraction
     * @param enterFragment         需要加载的fraction
     * @param isRemoveFragmentFroup 是否需要清除退出的fraction对应得所有分组
     */
    public void startFragmentAnimal(FractionManager fractionManager,
                                    MiFraction exitFragment,
                                    MiFraction enterFragment,
                                    boolean isRemoveFragmentFroup) {
        if (enterFragment.getComponent() == null) {
            FractionScheduler fractionScheduler = fractionManager.startFractionScheduler();
            fractionScheduler.add(enterFragment.getParentId(), enterFragment);
            enterFragment.setNeedWaitAnimal(true);
            fractionScheduler.submit();
        }
        initEnterFragment(enterFragment);
        animatorValue.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float value) {
                enterFragment(enterFragment, enterFragment.getComponent(), value);
                exitFragment(exitFragment, exitFragment.getComponent(), value);
                if (value == 1) {
                    fractionManager.startFractionScheduler().remove(exitFragment).submit();
                    enterFragment.animalEnd();
                    if (isRemoveFragmentFroup) {
                        removeAllFragmentByGroup(exitFragment.toString());
                    }
                }
            }
        });
    }

    private void initEnterFragment(MiFraction enterFragment) {
        if (enterFragment.getEnterAnimal() == TransitionAnimation.RIRHT) {
            enterFragment.getComponent().setTranslationX(enterFragment.getComponent().getEstimatedWidth());
        } else {
            enterFragment.getComponent().setTranslationX(-enterFragment.getComponent().getEstimatedWidth());
        }
    }

    private void enterFragment(MiFraction enterFragment, Component enterComponent, float value) {
        if (enterFragment.getEnterAnimal() == TransitionAnimation.RIRHT) {
            if (enterComponent != null) {
                enterComponent.setTranslationX((float) (enterComponent.getEstimatedWidth() * (1 - (double) value)));
            }
            return;
        }
        if (enterFragment.getEnterAnimal() == TransitionAnimation.LEFT) {
            if (enterComponent != null) {
                enterComponent.setTranslationX((float) (-enterComponent.getEstimatedWidth() * (1 - (double) value)));
            }
            return;
        }
    }

    private void exitFragment(MiFraction exitFragment, Component exitComponent, float value) {
        if (exitFragment.getOutAnimal() == TransitionAnimation.LEFT) {
            if (exitComponent != null) {
                exitComponent.setTranslationX((float) (-exitComponent.getEstimatedWidth() * (double) value));
            }
            return;
        }
        if (exitFragment.getOutAnimal() == TransitionAnimation.RIRHT) {
            if (exitComponent != null) {
                exitComponent.setTranslationX((float) (exitComponent.getEstimatedWidth() * (double) value));
            }
        }
    }
}
